package com.fowo.api.walmart.api;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.datainterface.constants.Constants;
import com.fowo.api.datainterface.service.impl.DatainterfaceServiceImpl;
import com.fowo.api.entity.ShopInfo;
import com.fowo.api.entity.TmpWalmartItem;
import com.fowo.api.mapper.ShopInfoMapper;
import com.fowo.api.service.impl.TmpWalmartItemServiceImpl;
import com.fowo.api.service.impl.TmpWalmartOrderGoodsServiceImpl;
import com.fowo.api.service.impl.TmpWalmartOrderServiceImpl;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.service.FileService;
import com.fowo.api.walmart.config.WalmartCsvReadConfig;
import com.fowo.api.walmart.util.WalmartUtil;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Component
@Slf4j
public class WalmartItemApi {

    @Resource
    private ShopInfoMapper shopInfoMapper;
    @Resource
    private TmpWalmartItemServiceImpl tmpWalmartItemService;
    @Resource
    private FileService fileService;
    @Resource
    private DatainterfaceServiceImpl datainterfaceService;

    private static final String REPORT_URL = "https://marketplace.walmartapis.com/v3/reports/reportRequests";
    private static final String REPORT_DOWNLOAD_URL = "https://marketplace.walmartapis.com/v3/reports/downloadReport";


    /**
     * 获取沃尔玛商品
     * 1、创建报表
     * 2、检查报表是否创建完成（15到45分钟能创建好）
     * 3、创建完成之后获取报表URL
     * 4、根据报表URL下载zip文件解析商品数据并插入临时表
     * @throws Exception
     */
    public void itemReport() throws Exception {
        final List<ShopInfo> shopInfos = shopInfoMapper.selectList(Wrappers.lambdaQuery(ShopInfo.class)
                .eq(ShopInfo::getPlatform, "Walmart")
                .eq(ShopInfo::getSellerAuthStatus, "SQ01"));
        for(ShopInfo shopInfo : shopInfos){
            try{

                String token = WalmartUtil.getToken(shopInfo.getMarketplaceId(),shopInfo.getRefreshToken());
                String requestId = createReport(token);
//            String requestId = "a11a9c3d-0f51-4dc9-8836-2da1fcdd9ef5";
                if(checkReportStatus(shopInfo,requestId)) {
                    String url = getDownloadUrl(shopInfo,requestId);
                    download(url,shopInfo.getId());
                }
            }catch (Exception e){
                log.error("店铺："+shopInfo.getShopName()+" 拉取商品数据异常",e);
            }
        }
    }

    public String createReport(String token){
        Map<String,Object> header = new HashMap<>();
        header.put("WM_SEC.ACCESS_TOKEN",token);
        header.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString());
        header.put("WM_SVC.NAME","Walmart Marketplace");
        header.put("Accept","application/json");
        header.put("Content-Type","application/json");

//        Object result = WalmartUtil.getBaseAspect().httpRequest(REPORT_URL+"?reportType=ITEM&reportVersion=v4", HttpMethod.POST, null, header, Object.class, Constants.Read, StrUtil.EMPTY);
        Object result = datainterfaceService.executeInterface(null, "EC00533", null, null, header);
        JSONObject body = JSONUtil.parseObj(result);
        log.info("创建商品报表返回参数：{}",JSONUtil.toJsonStr(body));
        return body.getStr("requestId");
    }

    public boolean checkReportStatus(ShopInfo shopInfo,String requestId) throws Exception {
        String token = WalmartUtil.getToken(shopInfo.getMarketplaceId(),shopInfo.getRefreshToken());
        Map<String,Object> header = new HashMap<>();
        header.put("WM_SEC.ACCESS_TOKEN",token);
        header.put("WM_QOS.CORRELATION_ID",UUID.randomUUID().toString());
        header.put("WM_SVC.NAME","Walmart Marketplace");
        header.put("Accept","application/json");
//        Object result = WalmartUtil.getBaseAspect().httpRequest(REPORT_URL+"/"+requestId, HttpMethod.GET, null, header, Object.class, Constants.Read, StrUtil.EMPTY);
        Map<String,Object> param = new HashMap<>();
        param.put("path",requestId);
        Object result = datainterfaceService.executeInterface(null, "EC00534", null, param, header);
        JSONObject body = JSONUtil.parseObj(result);
        log.info("检查商品报表返回参数：{}",JSONUtil.toJsonStr(body));
        final String requestStatus = body.getStr("requestStatus");
        switch (requestStatus){
            case "RECEIVED":
            case "INPROGRESS":
                Thread.currentThread().sleep(600000); //等600S再请求
                return checkReportStatus(shopInfo,requestId);
            case "READY":
                return true;
            case "ERROR":
                throw new Exception("获取商品报告异常");
            default:
                throw new Exception("商品报告状态异常");
        }
    }

    public String getDownloadUrl(ShopInfo shopInfo,String requestId){
        String token = WalmartUtil.getToken(shopInfo.getMarketplaceId(),shopInfo.getRefreshToken());
        Map<String,Object> header = new HashMap<>();
        header.put("WM_SEC.ACCESS_TOKEN",token);
        header.put("WM_QOS.CORRELATION_ID",UUID.randomUUID().toString());
        header.put("WM_SVC.NAME","Walmart Marketplace");
        header.put("Accept","application/json");

//        Object result = WalmartUtil.getBaseAspect().httpRequest(REPORT_DOWNLOAD_URL+"?requestId="+requestId, HttpMethod.GET, null, header, Object.class, Constants.Read, StrUtil.EMPTY);
        Map<String,Object> param = new HashMap<>();
        param.put("requestId",requestId);
        Object result = datainterfaceService.executeInterface(null, "EC00535", null, param, header);
        JSONObject body = JSONUtil.parseObj(result);
        log.info("下载商品报表返回参数：{}",JSONUtil.toJsonStr(body));
        return body.getStr("downloadURL");
    }

    public void download(String url, Long sid) throws IOException, IllegalArgumentException {
        OkHttpClient httpclient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();

        Response response = httpclient.newCall(request).execute();
        if (!response.isSuccessful()) {
            System.out.println(
                    String.format("Call to download content was unsuccessful with response code: %d and message: %s",
                            response.code(), response.message()));
            return;
        }

        try (ResponseBody responseBody = response.body()) {

            Closeable closeThis = null;
            try {
                InputStream inputStream = responseBody.byteStream();
                ZipInputStream zipInputStream = new ZipInputStream(inputStream);
                closeThis = zipInputStream;
                ZipEntry nextEntry;
                List<TmpWalmartItem> tmpWalmartItems = new ArrayList<>();
                while ((nextEntry = zipInputStream.getNextEntry())!= null){
                    if(nextEntry.getName().endsWith(".csv")){
                        Reader reader = new InputStreamReader(zipInputStream);
                        final CsvReader csvReader = CsvUtil.getReader(reader, WalmartCsvReadConfig.setItemReadConfig());
                        csvReader.read().getRows().forEach(csvRow->{
                            TmpWalmartItem item = new TmpWalmartItem();
                            item.setSid(sid);
                            item.setCreateTime(new Date());
                            item.setLastUpdateTime(new Date());
//                            System.out.println(csvRow.getByName("msku"));
                            item.setMsku(csvRow.get(0));
                            item.setItemId(csvRow.get(1));
                            item.setTitle(csvRow.get(2));
                            item.setLifecycleStatus(csvRow.get(3));
                            item.setPublishedStatus(csvRow.get(4));
                            item.setStatusChangeReason(csvRow.get(5));
                            item.setProductCategory(csvRow.get(6));
                            item.setPriceAmount(StrUtil.isEmpty(csvRow.get(7))?null:new BigDecimal(csvRow.get(7)));
                            item.setPriceCurrency(csvRow.get(8));
                            item.setBuyBoxItemPrice(StrUtil.isEmpty(csvRow.get(9))?null:new BigDecimal(csvRow.get(9)));
                            item.setBuyBoxShippingPrice(StrUtil.isEmpty(csvRow.get(10))?null:new BigDecimal(csvRow.get(10)));
                            item.setBuyBoxEligible(csvRow.get(11));
                            item.setMsrp(csvRow.get(12));
                            item.setProductTaxCode(csvRow.get(13));
                            item.setShipMethods(csvRow.get(14));
                            item.setShippingWeight(StrUtil.isEmpty(csvRow.get(15))?null:new BigDecimal(csvRow.get(15)));
                            item.setShippingWeightUnit(csvRow.get(16).replaceAll("\"",""));
                            item.setFulfillmentLagTime(StrUtil.isEmpty(csvRow.get(17))?null:Integer.valueOf(csvRow.get(17)));
                            item.setFulfillmentType(csvRow.get(18));
                            item.setWfsSalesRestriction(csvRow.get(19));
                            item.setWpid(csvRow.get(20));
                            item.setGtin(csvRow.get(21));
                            item.setUpc(csvRow.get(22));
                            item.setItemPageUrl(csvRow.get(23));
                            item.setPrimaryImageUrl(csvRow.get(24));
                            item.setShelfName(csvRow.get(25));
                            item.setPrimaryCategoryPath(csvRow.get(26));
                            item.setBrand(csvRow.get(27));
                            item.setOfferStartDate(StrUtil.isEmpty(csvRow.get(28))?null: DateUtil.parse(csvRow.get(28),"MM/dd/yyyy"));
                            item.setOfferEndDate(StrUtil.isEmpty(csvRow.get(29))?null:DateUtil.parse(csvRow.get(29),"MM/dd/yyyy"));
                            item.setItemCreationDate(StrUtil.isEmpty(csvRow.get(30))?null:DateUtil.parse(csvRow.get(30),"MM/dd/yyyy"));
                            item.setItemLastUpdated(StrUtil.isEmpty(csvRow.get(31))?null:DateUtil.parse(csvRow.get(31),"MM/dd/yyyy"));
                            item.setReviewsCount(StrUtil.isEmpty(csvRow.get(32))?null:Integer.valueOf(csvRow.get(32)));
                            item.setAverageRating(csvRow.get(33));
                            item.setSearchable(csvRow.get(34));
                            item.setVariantGroupId(csvRow.get(35));
                            item.setPrimaryVariant(csvRow.get(36));
                            item.setVariantGroupingAttributes(csvRow.get(37));
                            item.setVariantGroupingValues(csvRow.get(38));
                            item.setCompetitorUrl(csvRow.get(39));
                            item.setCompetitorPrice(StrUtil.isEmpty(csvRow.get(40))?null:new BigDecimal(csvRow.get(40)));
                            item.setCompetitorShipPrice(StrUtil.isEmpty(csvRow.get(41))?null:new BigDecimal(csvRow.get(41)));
                            item.setCompetitorLastDateFetched(StrUtil.isEmpty(csvRow.get(42))?null:DateUtil.parse(csvRow.get(42),"MM/dd/yyyy"));
                            item.setRepricerStrategy(csvRow.get(43));
                            item.setMinimumSellerAllowedPrice(StrUtil.isEmpty(csvRow.get(44))?null:new BigDecimal(csvRow.get(44)));
                            item.setMaximumSellerAllowedPrice(StrUtil.isEmpty(csvRow.get(45))?null:new BigDecimal(csvRow.get(45)));
                            item.setRepricerStatus(csvRow.get(46));

                            if(StringUtils.isNotBlank(item.getPrimaryImageUrl())){
                                item.setImage(uploadImage(item.getPrimaryImageUrl()));
                            }
                            tmpWalmartItems.add(item);
                        });
                    }
                }
                tmpWalmartItemService.saveBatch(tmpWalmartItems);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                log.error("处理沃尔玛商品数据异常",e);
            } finally {
                if (closeThis != null) {
                    closeThis.close();
                }
            }
        }
    }

    public List<SysFile> uploadImage(String picUrl) {
        List<SysFile> fileList = new ArrayList<>();
        if (picUrl != null && !picUrl.isEmpty()) {
            MultipartFile multipartFile = null;
            try {
                multipartFile = onlineAddressTransferFile(picUrl);
                if (multipartFile != null) {
                    SysFile file = fileService.upload(multipartFile, null);
                    fileList.add(file);
                }
            } catch (Exception e) {
                log.error("上传失败：" + picUrl, e);
            }
        }
        return fileList;
    }

    public MultipartFile onlineAddressTransferFile(String strUrl) throws IOException {
        InputStream stream = getInputStreamByUrl(strUrl);
        if (!ObjectUtils.isEmpty(stream)) {
            return new MockMultipartFile("网络图片", FileUtil.getName(strUrl), "image/jpeg", stream);
        } else {
            log.error("获取网络文件失败 > " + strUrl);
        }
        return null;
    }

    public InputStream getInputStreamByUrl(String strUrl) {
        HttpURLConnection conn = null;
        try {
            if (org.apache.commons.lang3.StringUtils.isNotBlank(strUrl)) {
                URL url = new URL(strUrl);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(20 * 1000);

                final ByteArrayOutputStream output = new ByteArrayOutputStream();
                InputStream inputStream = conn.getInputStream();
                IOUtils.copy(inputStream, output);
                return new ByteArrayInputStream(output.toByteArray());
            }
        } catch (FileNotFoundException e) {
            log.error("FileNotFoundException: " + strUrl);
        } catch (Exception e) {
//            e.printStackTrace();
            log.error("获取图片时失败，未知异常: " + strUrl, e);
        } finally {
            try {
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                log.error("获取图片时，连接失败: " + strUrl, e);
            }
        }
        return null;
    }
}
